#include "lanservice.h"

LANService* LANService::instance = nullptr;

LANService* LANService::getInstance()
{
    if (!instance) {
        instance = new LANService();
    }
    return instance;
}

LANService::LANService(QObject *parent) : QObject(parent),
    socket(nullptr), 
    broadcastTimer(nullptr),
    discoveryTimer(nullptr),
    checkAliveTimer(nullptr),
    servicePort(0),
    isServer(false)
{
    socket = new QUdpSocket(this);
    
    broadcastTimer = new QTimer(this);
    discoveryTimer = new QTimer(this);
    checkAliveTimer = new QTimer(this);
    
    connect(socket, &QUdpSocket::readyRead, this, &LANService::processDatagrams);
    connect(broadcastTimer, &QTimer::timeout, this, &LANService::broadcastServerPresence);
    connect(discoveryTimer, &QTimer::timeout, this, &LANService::broadcastDiscoveryRequest);
    connect(checkAliveTimer, &QTimer::timeout, this, &LANService::checkServerTimeout);
    
    LOG_INFO("LAN服务初始化完成");
}

LANService::~LANService()
{
    stopServerBroadcast();
    stopClientDiscovery();
    
    if (socket) {
        socket->close();
    }
}

bool LANService::startServerBroadcast(quint16 port, const QString &name)
{
    if (isServer) {
        LOG_WARNING("LAN服务已经以服务器模式运行");
        return true;
    }
    
    // 如果正在进行客户端发现，先停止
    if (discoveryTimer->isActive()) {
        stopClientDiscovery();
    }
    
    // 重新绑定UDP端口
    if (socket->state() == QAbstractSocket::BoundState) {
        socket->close();
    }
    
    if (!socket->bind(LAN_DISCOVERY_PORT, QUdpSocket::ShareAddress)) {
        LOG_ERROR(QString("无法绑定UDP发现端口 %1: %2").arg(LAN_DISCOVERY_PORT).arg(socket->errorString()));
        return false;
    }
    
    servicePort = port;
    serverName = name.isEmpty() ? QHostInfo::localHostName() : name;
    isServer = true;
    
    // 开始定时广播
    broadcastTimer->start(5000);  // 每5秒广播一次
    
    LOG_INFO(QString("服务端广播已启动，服务端口: %1, 服务名称: %2").arg(servicePort).arg(serverName));
    
    // 立即广播一次
    broadcastServerPresence();
    
    return true;
}

void LANService::stopServerBroadcast()
{
    if (!isServer) {
        return;
    }
    
    broadcastTimer->stop();
    isServer = false;
    
    LOG_INFO("服务端广播已停止");
}

bool LANService::startClientDiscovery()
{
    if (!isServer && discoveryTimer->isActive()) {
        LOG_WARNING("客户端发现已经在运行");
        return true;
    }
    
    // 如果正在进行服务器广播，先停止
    if (isServer) {
        stopServerBroadcast();
    }
    
    // 重新绑定UDP端口
    if (socket->state() == QAbstractSocket::BoundState) {
        socket->close();
    }
    
    if (!socket->bind(LAN_DISCOVERY_PORT, QUdpSocket::ShareAddress)) {
        LOG_ERROR(QString("无法绑定UDP发现端口 %1: %2").arg(LAN_DISCOVERY_PORT).arg(socket->errorString()));
        return false;
    }
    
    isServer = false;
    
    // 清空已发现的服务器列表
    discoveredServers.clear();
    
    // 开始定时发送发现请求
    discoveryTimer->start(3000);  // 每3秒发送一次
    
    // 开始定时检查服务器是否在线
    checkAliveTimer->start(10000);  // 每10秒检查一次
    
    LOG_INFO("客户端发现已启动");
    
    // 立即发送一次发现请求
    broadcastDiscoveryRequest();
    
    return true;
}

void LANService::stopClientDiscovery()
{
    if (isServer) {
        return;
    }
    
    discoveryTimer->stop();
    checkAliveTimer->stop();
    
    LOG_INFO("客户端发现已停止");
}

QList<QPair<QString, quint16>> LANService::getDiscoveredServers() const
{
    QList<QPair<QString, quint16>> result;
    
    for (auto it = discoveredServers.constBegin(); it != discoveredServers.constEnd(); ++it) {
        result.append(qMakePair(it.key(), it.value().first.first));
    }
    
    return result;
}

QStringList LANService::getLocalIPAddresses()
{
    QStringList addresses;
    
    for (const QHostAddress &address : QNetworkInterface::allAddresses()) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol && 
            address != QHostAddress::LocalHost &&
            address.toString().startsWith("192.168.")) {
            addresses.append(address.toString());
        }
    }
    
    return addresses;
}

void LANService::processDatagrams()
{
    while (socket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(socket->pendingDatagramSize());
        
        QHostAddress sender;
        quint16 senderPort;
        
        socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        
        // 忽略来自自己的消息
        bool isLocalAddress = false;
        for (const QString &local : getLocalIPAddresses()) {
            if (sender.toString() == local) {
                isLocalAddress = true;
                break;
            }
        }
        
        if (isLocalAddress && isServer) {
            continue;
        }
        
        // 解析JSON数据
        QJsonParseError parseError;
        QJsonDocument doc = QJsonDocument::fromJson(datagram, &parseError);
        
        if (parseError.error != QJsonParseError::NoError) {
            LOG_WARNING(QString("收到无效的LAN发现数据: %1").arg(parseError.errorString()));
            continue;
        }
        
        QJsonObject message = doc.object();
        
        if (!message.contains("type")) {
            LOG_WARNING("收到格式错误的LAN发现消息");
            continue;
        }
        
        QString typeStr = message["type"].toString();
        DiscoveryType type;
        
        if (typeStr == "broadcast") {
            type = DiscoveryType::Broadcast;
        } else if (typeStr == "response") {
            type = DiscoveryType::Response;
        } else if (typeStr == "heartbeat") {
            type = DiscoveryType::Heartbeat;
        } else {
            LOG_WARNING(QString("未知的LAN发现消息类型: %1").arg(typeStr));
            continue;
        }
        
        // 处理不同类型的消息
        switch (type) {
        case DiscoveryType::Broadcast:
            if (isServer) {
                handleDiscoveryRequest(sender, senderPort);
            }
            break;
        case DiscoveryType::Response:
        case DiscoveryType::Heartbeat:
            if (!isServer) {
                handleResponseMessage(sender, message);
            }
            break;
        }
    }
}

void LANService::broadcastServerPresence()
{
    if (!isServer) {
        return;
    }
    
    sendDiscoveryMessage(DiscoveryType::Heartbeat);
}

void LANService::broadcastDiscoveryRequest()
{
    if (isServer) {
        return;
    }
    
    sendDiscoveryMessage(DiscoveryType::Broadcast);
}

void LANService::checkServerTimeout()
{
    if (isServer) {
        return;
    }
    
    QDateTime now = QDateTime::currentDateTime();
    QList<QString> serversToRemove;
    
    for (auto it = discoveredServers.begin(); it != discoveredServers.end(); ++it) {
        QDateTime lastSeen = it.value().first.second;
        
        // 如果30秒内没有收到服务器心跳，则认为服务器离线
        if (lastSeen.secsTo(now) > 30) {
            serversToRemove.append(it.key());
        }
    }
    
    // 移除超时的服务器
    for (const QString &server : serversToRemove) {
        quint16 port = discoveredServers[server].first.first;
        discoveredServers.remove(server);
        
        LOG_INFO(QString("服务器 %1:%2 已离线").arg(server).arg(port));
        emit serverLost(server, port);
    }
}

void LANService::sendDiscoveryMessage(DiscoveryType type)
{
    QJsonObject message;
    
    switch (type) {
    case DiscoveryType::Broadcast:
        message["type"] = "broadcast";
        break;
    case DiscoveryType::Response:
        message["type"] = "response";
        message["port"] = (int)servicePort;
        message["name"] = serverName;
        break;
    case DiscoveryType::Heartbeat:
        message["type"] = "heartbeat";
        message["port"] = (int)servicePort;
        message["name"] = serverName;
        break;
    }
    
    QJsonDocument doc(message);
    QByteArray data = doc.toJson(QJsonDocument::Compact);
    
    // 广播到局域网
    socket->writeDatagram(data, QHostAddress::Broadcast, LAN_DISCOVERY_PORT);
    
    // 遍历所有本地IP，并发送到所有可能的广播地址
    for (const QString &ip : getLocalIPAddresses()) {
        QStringList parts = ip.split('.');
        if (parts.size() == 4) {
            // 构造广播地址，如192.168.1.255
            parts[3] = "255";
            QString broadcastAddr = parts.join('.');
            socket->writeDatagram(data, QHostAddress(broadcastAddr), LAN_DISCOVERY_PORT);
        }
    }
}

void LANService::handleDiscoveryRequest(const QHostAddress &sender, quint16 senderPort)
{
    LOG_INFO(QString("收到来自 %1:%2 的发现请求").arg(sender.toString()).arg(senderPort));
    
    // 发送响应
    QJsonObject response;
    response["type"] = "response";
    response["port"] = (int)servicePort;
    response["name"] = serverName;
    
    QJsonDocument doc(response);
    QByteArray data = doc.toJson(QJsonDocument::Compact);
    
    socket->writeDatagram(data, sender, senderPort);
    
    LOG_INFO(QString("已发送响应到 %1:%2").arg(sender.toString()).arg(senderPort));
}

void LANService::handleResponseMessage(const QHostAddress &sender, const QJsonObject &data)
{
    if (!data.contains("port") || !data.contains("name")) {
        LOG_WARNING("收到格式错误的服务器响应");
        return;
    }
    
    quint16 port = data["port"].toInt();
    QString name = data["name"].toString();
    QString address = sender.toString();
    
    QDateTime now = QDateTime::currentDateTime();
    
    // 更新服务器列表
    bool isNew = !discoveredServers.contains(address);
    
    if (isNew || discoveredServers[address].first.first != port) {
        discoveredServers[address] = qMakePair(qMakePair(port, now), name);
        
        LOG_INFO(QString("发现服务器: %1:%2 (%3)").arg(address).arg(port).arg(name));
        emit serverDiscovered(address, port, name);
    } else {
        // 更新最后发现时间
        discoveredServers[address].first.second = now;
    }
} 